import 'package:flutter/material.dart';

abstract class SelectionOption {
  String get description;
}

typedef void OnSelectDone<T extends SelectionOption>(dynamic options);

class SelectionPanelWidget<T extends SelectionOption> extends StatefulWidget {
  final bool singleOption;

  final Iterable<T> options;
  final List<T>? initialSelectedOptions;

  final TextStyle selectedStyle;
  final TextStyle unselectedStyle;

  final IconData selectedIcon;
  final IconData unselectedIcon;

  final Color selectedBackgroundColor;

  final OnSelectDone onSelectDone;

  final double height;

  final EdgeInsets margin;

  final double buttonHeight;
  final double iconSize;

  const SelectionPanelWidget({
    Key? key,
    this.singleOption = false,
    required this.options,
    required this.onSelectDone,
    this.selectedStyle = const TextStyle(
      fontSize: 12,
      color: Colors.black,
      fontWeight: FontWeight.w500,
    ),
    this.unselectedStyle = const TextStyle(
      fontSize: 12,
      color: Colors.black,
      fontWeight: FontWeight.w500,
    ),
    this.selectedIcon = Icons.check_circle,
    this.unselectedIcon = Icons.check_circle_outline,
    this.selectedBackgroundColor = const Color(0xffE5EED2),
    this.height = 40.0,
    this.margin = const EdgeInsets.symmetric(horizontal: 16),
    this.buttonHeight = 24.0,
    this.iconSize = 16.0,
    this.initialSelectedOptions,
  }) : super(key: key);

  @override
  _SelectionPanelWidgetState createState() =>
      _SelectionPanelWidgetState(this.initialSelectedOptions);
}

class _SelectionPanelWidgetState<T extends SelectionOption>
    extends State<SelectionPanelWidget> {
  List<T>? selectedOptions;

  _SelectionPanelWidgetState(this.selectedOptions) {
    selectedOptions ??= [];
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: widget.margin,
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.only(
          bottomLeft: Radius.circular(8.0),
          bottomRight: Radius.circular(8.0),
        ),
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          ListView(
            shrinkWrap: true,
            children: <Widget>[
              for (final option in widget.options)
                InkWell(
                  child: Container(
                    padding: EdgeInsets.symmetric(horizontal: 16.0),
                    height: widget.height,
                    color: _isSelected(option as T)
                        ? widget.selectedBackgroundColor
                        : Colors.white,
                    child: Row(
                      children: <Widget>[
                        buildCheckbox(context, _isSelected(option)),
                        SizedBox(width: 8),
                        Text(
                          option.description,
                          style: _isSelected(option)
                              ? widget.selectedStyle
                              : widget.unselectedStyle,
                        )
                      ],
                    ),
                  ),
                  onTap: () {
                    _toggleSelection(option);
                  },
                ),
            ],
          ),
          if (widget.singleOption == false) ...[
            Divider(height: 1),
            SizedBox(height: 8.0),
            Row(
              children: <Widget>[
                InkWell(
                  child: Row(
                    children: <Widget>[
                      SizedBox(width: 16),
                      buildCheckbox(context, _isAllSelected()),
                      SizedBox(width: 8),
                      Text(
                        "全选",
                        style: _isAllSelected()
                            ? widget.selectedStyle
                            : widget.unselectedStyle,
                      ),
                    ],
                  ),
                  onTap: _toggleSelectAll,
                ),
                Spacer(),
                SizedBox(
                  height: widget.buttonHeight,
                  child: OutlinedButton(
                    style: OutlinedButton.styleFrom(
                      shape: StadiumBorder(),
                      side: BorderSide(color: Theme.of(context).primaryColor),
                      textStyle:
                          TextStyle(color: Theme.of(context).primaryColor),
                    ),
                    child: Text("取消"),
                    onPressed: () {
                      widget.onSelectDone(null);
                    },
                  ),
                ),
                SizedBox(width: 8),
                SizedBox(
                  height: widget.buttonHeight,
                  child: ElevatedButton(
                    style: ElevatedButton.styleFrom(
                      shape: StadiumBorder(),
                    ),
                    child: Text(
                      "确定",
                      style: TextStyle(color: Colors.white),
                    ),
                    onPressed: () {
                      widget.onSelectDone(selectedOptions);
                    },
                  ),
                ),
                SizedBox(width: 16),
              ],
            ),
            SizedBox(height: 8)
          ]
        ],
      ),
    );
  }

  Widget buildCheckbox(BuildContext context, bool checked) {
    return Icon(
      checked ? widget.selectedIcon : widget.unselectedIcon,
      color: checked ? Theme.of(context).primaryColor : Colors.grey,
      size: widget.iconSize,
    );
  }

  bool _isSelected(T option) {
    return selectedOptions!.contains(option);
  }

  void _toggleSelection(T option) {
    if (widget.singleOption == true) {
      widget.onSelectDone(option);
    } else {
      setState(() {
        if (selectedOptions!.contains(option)) {
          selectedOptions!.remove(option);
        } else {
          selectedOptions!.add(option);
        }
      });
    }
  }

  bool _isAllSelected() {
    return selectedOptions!.length == widget.options.length;
  }

  void _toggleSelectAll() {
    setState(() {
      if (_isAllSelected()) {
        selectedOptions!.clear();
      } else {
        selectedOptions!.addAll(widget.options as Iterable<T>);
      }
    });
  }
}
